package com.cgwx.commonutils.math;

import com.cgwx.commonutils.math.function.*;

/**
 * @author GaoWei
 * @Date 2021/8/6 - 9:19
 */
public class FuncMap
{
//    函数名字的字符串数组
    private String[] name = new String[50];
//    函数数组
    private Function[] func = new Function[50];
//    函数的数量
    private int numFunc = 0;
//    是否区分大小写
    private boolean caseSensitive = false;

    public FuncMap()
    {
    }

    public FuncMap(boolean caseSensitive)
    {
        this.caseSensitive = caseSensitive;
    }

    public void loadDefaultFunctions()
    {
        setFunction("min", new MinFunction());
        setFunction("max", new MaxFunction());
        setFunction("sum", new SumFunction());
        setFunction("avg", new AvgFunction());
        setFunction("pi", new PiFunction());
        setFunction("e", new EFunction());
        setFunction("rand", new RandFunction());
        setFunction("sin", new SinFunction());
        setFunction("cos", new CosFunction());
        setFunction("tan", new TanFunction());
        setFunction("sqrt", new SqrtFunction());
        setFunction("abs", new AbsFunction());
        setFunction("ceil", new CeilFunction());
        setFunction("floor", new FloorFunction());
        setFunction("exp", new ExpFunction());
        setFunction("lg", new LgFunction());
        setFunction("ln", new LnFunction());
        setFunction("sign", new SignFunction());
        setFunction("round", new RoundFunction());
        setFunction("fact", new FactFunction());
        setFunction("cosh", new CoshFunction());
        setFunction("sinh", new SinhFunction());
        setFunction("tanh", new TanhFunction());
        setFunction("acos", new AcosFunction());
        setFunction("asin", new AsinFunction());
        setFunction("atan", new AtanFunction());
        setFunction("acosh", new AcoshFunction());
        setFunction("asinh", new AsinhFunction());
        setFunction("atanh", new AtanhFunction());
        setFunction("pow", new PowFunction());
        setFunction("mod", new ModFunction());
        setFunction("combin", new CombinFunction());
        setFunction("log", new LogFunction());
    }

    public Function getFunction(String funcName, int numParam) {
        for (int i = 0; i < this.numFunc; i++) {
            if ((this.func[i].acceptNumParam(numParam)) && (((this.caseSensitive) && (this.name[i].equals(funcName))) || ((!this.caseSensitive) && (this.name[i].equalsIgnoreCase(funcName))))) {
                return this.func[i];
            }
        }
        throw new RuntimeException("function not found: " + funcName + " " + numParam);
    }

    public void setFunction(String funcName, Function f) {
        if (funcName == null) {
            throw new IllegalArgumentException("function name cannot be null");
        }
        if (f == null) {
            throw new IllegalArgumentException("function cannot be null");
        }
        for (int i = 0; i < this.numFunc; i++) {
            if (((this.caseSensitive) && (this.name[i].equals(funcName))) || ((!this.caseSensitive) && (this.name[i].equalsIgnoreCase(funcName)))) {
                this.func[i] = f;
                return;
            }
        }
        if (this.numFunc == this.name.length) {
            String[] tmp1 = new String[2 * this.numFunc];
            Function[] tmp2 = new Function[tmp1.length];
            for (int i = 0; i < this.numFunc; i++) {
                tmp1[i] = this.name[i];
                tmp2[i] = this.func[i];
            }
            this.name = tmp1;
            this.func = tmp2;
        }
        this.name[this.numFunc] = funcName;
        this.func[this.numFunc] = f;
        this.numFunc += 1;
    }

    public boolean isCaseSensitive()
    {
        return this.caseSensitive;
    }

    public String[] getFunctionNames() {
        String[] arr = new String[this.numFunc];
        if (arr.length >= 0) System.arraycopy(this.name, 0, arr, 0, arr.length);
        return arr;
    }

    public Function[] getFunctions() {
        Function[] arr = new Function[this.numFunc];
        if (arr.length >= 0) System.arraycopy(this.func, 0, arr, 0, arr.length);
        return arr;
    }

    public void remove(String funcName) {
        for (int i = 0; i < this.numFunc; i++) {
            if (((this.caseSensitive) && (this.name[i].equals(funcName))) || ((!this.caseSensitive) && (this.name[i].equalsIgnoreCase(funcName)))) {
                for (int j = i + 1; j < this.numFunc; j++) {
                    this.name[(j - 1)] = this.name[j];
                    this.func[(j - 1)] = this.func[j];
                }
                this.numFunc -= 1;
                this.name[this.numFunc] = null;
                this.func[this.numFunc] = null;
                break;
            }
        }
    }
}
